package com.yuven.baselib.network;

import androidx.annotation.CallSuper;

import com.yuven.baselib.network.errorhandlecomponent.RxErrorHandlingCallAdapterFactory;
import com.yuven.baselib.network.interceptor.ConnectivityInterceptor;
import com.yuven.baselib.utils.Logger;

import java.net.Proxy;
import java.net.Socket;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509ExtendedTrustManager;
import javax.net.ssl.X509TrustManager;

import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.RequestBody;
import retrofit2.Converter;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.converter.scalars.ScalarsConverterFactory;


/**
 * Created by lzz on 2017/12/25.
 * api请求工具基类，新项目请继承次类新建一个单例，并且实现基类方法
 */

public abstract class RetrofitClientProvider {
    private RetrofitConfiguration mRetrofitConfiguration;
    private Retrofit mRetrofit;

    /**
     * 配置入口
     *
     * @param retrofitConfiguration
     */
    public void init(RetrofitConfiguration retrofitConfiguration) {
        this.mRetrofitConfiguration = retrofitConfiguration;
        initRetrofit();
        initService();
    }

    private void initRetrofit() {
        mRetrofit = new Retrofit.Builder()
                .client(getOkHttpClient())
                .addConverterFactory(ScalarsConverterFactory.create())
                .addConverterFactory(getGsonConverter())
                .addCallAdapterFactory(RxErrorHandlingCallAdapterFactory.create())
                .baseUrl(getBaseUrl())
                .build();
    }

    protected abstract String getBaseUrl();

    protected abstract void initService();

    @CallSuper
    protected void initHttpClientConfig(OkHttpClient.Builder builder) {
        builder.connectTimeout(mRetrofitConfiguration.getConnectTimeout(), TimeUnit.MILLISECONDS);
        builder.readTimeout(mRetrofitConfiguration.getConnectTimeout(), TimeUnit.MILLISECONDS);
    }

    @CallSuper
    protected void addInterceptor(OkHttpClient.Builder builder) {
        builder.addInterceptor(new ConnectivityInterceptor(mRetrofitConfiguration));
    }

    private OkHttpClient getOkHttpClient() {
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        initHttpClientConfig(builder);
        addInterceptor(builder);
        // 设置无代理模式，禁止网络抓包（WiFi代理）
        //builder.proxy(Proxy.NO_PROXY);
        //https请求校验证书
//        addVerifyHttpsHandler(builder);

        return builder.build();
    }

    @SuppressWarnings("unchecked")
    protected <T> T createService(Class<T> clazz) {
        T t = getRetrofit().create(clazz);
        return t;
    }

    public Retrofit getRetrofit() {
        return mRetrofit;
    }

    public static RequestBody createCustomJsonRequestBody(String json) {
        return RequestBody.create(MediaType.parse("application/json"), json);
    }

    protected Converter.Factory getGsonConverter() {
        return GsonConverterFactory.create();
    }

    protected RetrofitConfiguration getConfiguration() {
        return mRetrofitConfiguration;
    }

    /**
     * 增加校验https请求处理(单向)
     *
     * @param clientBuilder 需要增加校验https请求处理的OkHttpClient Builder
     */
    private void addVerifyHttpsHandler(OkHttpClient.Builder clientBuilder) {
        SSLContext sslContext = null;
        X509TrustManager x509TrustManager = null;
        try {
            sslContext = SSLContext.getInstance("TLSv1.2");
            KeyStore keyStore = KeyStore.getInstance("AndroidCAStore");
            keyStore.load(null);
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(keyStore);
            TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
            for (TrustManager trustManager : trustManagers) {
                if (trustManager instanceof X509TrustManager) {
                    x509TrustManager = (X509TrustManager) trustManager;
                }
            }
            //sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());
            sslContext.init(null, null, null);
        } catch (Exception e) {
            e.printStackTrace();
            sslContext = null;
        }

        if (sslContext != null) {
            if (x509TrustManager != null) {
                try {
                    clientBuilder.sslSocketFactory(sslContext.getSocketFactory(), x509TrustManager)
                            .hostnameVerifier(new HostnameVerifier() {
                                @Override
                                public boolean verify(String hostname, SSLSession session) {
                                    //return HttpsURLConnection.getDefaultHostnameVerifier().verify(hostname, session);
                                    return true;
                                }
                            });
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else {
                try {
                    clientBuilder.sslSocketFactory(sslContext.getSocketFactory())
                            .hostnameVerifier(new HostnameVerifier() {
                                @Override
                                public boolean verify(String hostname, SSLSession session) {
                                    //return HttpsURLConnection.getDefaultHostnameVerifier().verify(hostname, session);
                                    return true;
                                }
                            });
                } catch (Exception e) {
                    e.printStackTrace();
                    x509TrustManager = new X509TrustManager() {

                        @Override
                        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {

                        }

                        @Override
                        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                            for (X509Certificate cert : chain) {
                                // Make sure that it hasn't expired.
                                cert.checkValidity();
                            }
                        }

                        @Override
                        public X509Certificate[] getAcceptedIssuers() {
                            return new X509Certificate[0];
                        }
                    };

                    try {
                        clientBuilder.sslSocketFactory(sslContext.getSocketFactory(), x509TrustManager)
                                .hostnameVerifier(new HostnameVerifier() {
                                    @Override
                                    public boolean verify(String hostname, SSLSession session) {
                                        //return HttpsURLConnection.getDefaultHostnameVerifier().verify(hostname, session);
                                        return true;
                                    }
                                });
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                }
            }
        }
    }

}
